#include "encipher.h"
#include <QDebug>

Encipher* Encipher::encipher=nullptr;
QByteArray Encipher::aeskey=QByteArray();
QByteArray Encipher::aesiv=QByteArray();

Encipher::Encipher(){}

Encipher *Encipher::getInstance()
{
    if(!encipher)
    {
        encipher=new Encipher;
    }
    return encipher;
}

void Encipher::setAesiv(const QByteArray &vi)
{
    aesiv=vi;
}

void Encipher::setAesKey(const QByteArray &key)
{
    aeskey=key;
}


// 计算字符串的SHA-256哈希值
QByteArray Encipher::sha256(const QByteArray& input)
{
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, input.constData(), input.size());
    SHA256_Final(hash, &sha256);

    QByteArray output;
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        char buf[3];
        sprintf(buf, "%02x", hash[i]);
        output.append(buf);
    }

    return output;
}

bool Encipher::validate(const QByteArray &mes,const QByteArray& sha256value)
{
    QByteArray enciphe=sha256(mes);
    return sha256value==enciphe;
}

QByteArray Encipher::addPkcs7Padding(QByteArray data) {
    int paddingSize = AES_BLOCK_SIZE - (data.size() % AES_BLOCK_SIZE);
    QByteArray padding(paddingSize, static_cast<char>(paddingSize));
    return data.append(padding);
}

QByteArray Encipher::aesEncrypt(QByteArray data) {
    QByteArray key=aeskey;
    QByteArray iv=aesiv;
    // 确保密钥和IV长度正确
    if (key.size() != 32 || iv.size() != 16) {
        qDebug() << "Invalid key or IV size";
        return QByteArray();
    }

    // 添加PKCS#7填充

    QByteArray paddedData = addPkcs7Padding(data);

    // 初始化AES上下文
    AES_KEY aesKey;
    AES_set_encrypt_key((const unsigned char*)key.data(), 256, &aesKey);

    // 计算输出数据的大小
    int outLen = paddedData.size();
    QByteArray encrypted(outLen, '\0');

    // 执行CBC模式加密
    AES_cbc_encrypt((const unsigned char*)paddedData.data(), (unsigned char*)encrypted.data(), outLen,
                    &aesKey, (unsigned char*)iv.data(), AES_ENCRYPT);

    // 返回加密后的数据
    return encrypted;
}
QByteArray Encipher::aesEncrypt(const QByteArray& data, const QByteArray& key, const QByteArray& iv) {

    // 确保密钥和IV长度正确
    if (key.size() != 32 || iv.size() != 16) {
        qDebug() << "Invalid key or IV size";
        return QByteArray();
    }

    // 添加PKCS#7填充
    QByteArray paddedData = addPkcs7Padding(data);

    // 初始化AES上下文
    AES_KEY aesKey;
    AES_set_encrypt_key((const unsigned char*)key.data(), 256, &aesKey);

    // 计算输出数据的大小
    int outLen = paddedData.size();
    QByteArray encrypted(outLen, '\0');

    // 执行CBC模式加密
    AES_cbc_encrypt((const unsigned char*)paddedData.data(), (unsigned char*)encrypted.data(), outLen,
                    &aesKey, (unsigned char*)iv.data(), AES_ENCRYPT);

    // 返回加密后的数据
    return encrypted;
}

QByteArray Encipher::removePkcs7Padding(QByteArray data) {
    if (!data.isEmpty()) {
        quint8 padding = data.at(data.size() - 1);
        if (padding <= AES_BLOCK_SIZE) {
            bool isValidPadding = true;
            for (quint8 i = 1; i <= padding; ++i) {
                if (data.at(data.size() - i) != padding) {
                    isValidPadding = false;
                    break;
                }
            }
            if (isValidPadding) {
                data.chop(padding);
            }
        }
    }
    return data;
}
QByteArray Encipher::aesDecrypt(const QByteArray& data) {
    QByteArray key=aeskey;
    QByteArray iv=aesiv;
    // 确保密钥和IV长度正确
    if (key.size() != 32 || iv.size() != 16) {
        qCritical() << "Invalid key or IV size";
        return QByteArray();
    }

    // 初始化AES上下文
    AES_KEY aesKey;
    AES_set_decrypt_key((const unsigned char*)key.data(), 256, &aesKey);

    // 计算输出数据的大小
    int outLen = data.size();
    QByteArray decrypted(outLen, '\0');

    // 执行CBC模式解密
    AES_cbc_encrypt((const unsigned char*)data.data(), (unsigned char*)decrypted.data(), outLen,
                    &aesKey, (unsigned char*)iv.data(), AES_DECRYPT);

    // 移除PKCS#7填充
    decrypted = removePkcs7Padding(decrypted);

    // 返回解密后的数据
    return decrypted;
}
QByteArray Encipher::aesDecrypt(const QByteArray& data, const QByteArray& key, const QByteArray& iv) {
    // 确保密钥和IV长度正确
    if (key.size() != 32 || iv.size() != 16) {
        qCritical() << "Invalid key or IV size";
        return QByteArray();
    }

    // 初始化AES上下文
    AES_KEY aesKey;
    AES_set_decrypt_key((const unsigned char*)key.data(), 256, &aesKey);

    // 计算输出数据的大小
    int outLen = data.size();
    QByteArray decrypted(outLen, '\0');

    // 执行CBC模式解密
    AES_cbc_encrypt((const unsigned char*)data.data(), (unsigned char*)decrypted.data(), outLen,
                    &aesKey, (unsigned char*)iv.data(), AES_DECRYPT);

    // 移除PKCS#7填充
    decrypted = removePkcs7Padding(decrypted);

    // 返回解密后的数据
    return decrypted;
}

std::unique_ptr<QByteArray> Encipher::sha_aesDecrypt(const QByteArray &data)
{
    QByteArray* res=new QByteArray(aesDecrypt(data));
    return std::unique_ptr<QByteArray>(res);
}

std::unique_ptr<QByteArray> Encipher::sha_aesEncrypt(const QByteArray& data)
{
    QByteArray res=data;
    QByteArray sha256enciphe=sha256(data);
    res.append("#$^").append(sha256enciphe);
    QByteArray* final=new QByteArray(aesEncrypt(res));
    return std::unique_ptr<QByteArray>(final);
}
